(()=>{
  // 1、泛型 在定义函数、接口或类的时候，不预先指定具体的类型，而在使用的时候再指定具体类型的一种特性
  // 需求：根据指定的数量 count 和数据 value , 创建一个包含 count 个 value的数组
  // 不使用泛型
  function createArray(value: any, count: number): any[] {
    const arr: any[] = []
    for (let index = 0; index < count; index++) {
      arr.push(value)
    }
    return arr
  }
  
  const arr1 = createArray(11, 3)
  const arr2 = createArray('aa', 3)
  // console.log(arr1[0].toFixed(), arr2[0].split(''))//因为类型为any，编译器无法检查加智能提示

  // 使用泛型
  function createArray2 <T> (value: T, count: number) {
    const arr: Array<T> = []
    for (let index = 0; index < count; index++) {
      arr.push(value)
    }
    return arr
  }
  const arr3 = createArray2<number>(11, 3)
  // console.log(arr3[0].toFixed())
  // console.log(arr3[0].split('')) // error
  const arr4 = createArray2<string>('aa', 3)
  // console.log(arr4[0].split(''))
  // console.log(arr4[0].toFixed()) // error


  // 2、多个泛型参数的函数
  function fun<T,K>(a:T,b:K):[T,K]{
    return [a,b]
  }
  // console.log(fun<string,number>('1',3))
  // console.log(fun<boolean,string>(false,'5'))

  // 3、泛型接口 在定义接口时为接口中的属性或方法定义泛型类型，在使用接口的时候再指定具体的泛型类型
  interface IbaseCRUD<T>{
    data:T[]
    add(t:T)
    getById(id:number)
  }
  class User{
    id?:number
    name:string
    age:number
    constructor(name:string,age:number){
      this.name = name
      this.age = age
    }
  }
  class UserCRUD implements IbaseCRUD<User>{
    data:User[] = []
    add(user:User){
      user.id = Date.now()
      this.data.push(user)
    }
    getById(id:number):User|number{
      return this.data.find(user=>user.id === id) || -1
    }
  }
  let u:UserCRUD = new UserCRUD()
  u.add(new User('zs',20))
  u.add(new User('ls',22))
  u.add(new User('ww',28))
  // console.log(u.getById(Date.now()))
  u.add(new User('cl',11))
  u.add(new User('sq',30))
  // console.log(u.data)

  // 4、泛型类 在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型
  class GenericNumber<T> {
    zeroValue: T
    add: (x: T, y: T) => T
  }
  
  let myGenericNumber = new GenericNumber<number>()
  myGenericNumber.zeroValue = 0
  myGenericNumber.add = function(x, y) {
    return x + y 
  }
  
  let myGenericString = new GenericNumber<string>()
  myGenericString.zeroValue = 'abc'
  myGenericString.add = function(x, y) { 
    return x + y
  }
  
  // console.log(myGenericString.add(myGenericString.zeroValue, 'test'))
  // console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))


  // 5、泛型约束
  interface Lengthwise {
    length: number;
  }
  
  // 指定泛型约束
  function fn2 <T extends Lengthwise>(x: T): void {
    console.log(x.length)
  }
  // fn2('abc')
// fn2(123) // error  number没有length属性


})()